-- SPDX-License-Identifier: GPL-3.0-or-later
---@class StoryData: Object
local Map = class("Map")

-- Map.TypeStoryEnd = "storyend"

Map.NorMonster = 1
Map.EliteMonster = 2
Map.Boss = 3
Map.Box = 4
Map.Shop = 5
Map.OtherEvents = 6

Map.NorMonsterStr = "normonster"
Map.EliteMonsterStr = "elitemonster"
Map.BossStr = "boss"
Map.BoxStr = "box"
Map.ShopStr = "shop"
Map.OtherEventsStr = "otherevents"
Map.RestStr = "rest"
Map.AddMaxHp = "addmaxhp"
Map.GetPeach = "getcd-wdtx__peach"
Map.GetAnalep = "getcd-wdtx__analeptic"
Map.GetSlash = "getcd-wdtx__slash"
Map.GetNan = "getcd-wdtx__savage_assault"
Map.GetWan = "getcd-wdtx__archery_attack"
-- Map.NorMonsterArea = {5,7}
-- Map.EliteMonsterArea = {1,2}
-- Map.BoxArea = {2,3}
-- Map.ShopArea = {2,3}
-- Map.RestArea = {2,2}
-- Map.OtherEventsArea = {2,3}
Map.Enjoy = {
  [Map.NorMonsterStr] = "monster",
  [Map.EliteMonsterStr] = "elite",
  [Map.BoxStr] = "box",
  [Map.BossStr] = "boss",
  [Map.ShopStr] = "shop",
  [Map.RestStr] = "rest",
  [Map.OtherEventsStr] = "event",
  [Map.AddMaxHp] = "addmaxhp",
  [Map.GetPeach] = "getcard",
  [Map.GetAnalep] = "getcard",
  [Map.GetSlash] = "getcard",
  [Map.GetNan] = "getcard",
  [Map.GetWan] = "getcard",
}
Map.Translate = {
  [Map.NorMonsterStr] = "普通怪物",
  [Map.EliteMonsterStr] = "精英怪物",
  [Map.BoxStr] = "宝箱",
  [Map.BossStr] = "Boss",
  [Map.ShopStr] = "商店",
  [Map.RestStr] = "休息",
  [Map.OtherEventsStr] = "？？",
  [Map.AddMaxHp] = "鲜红的赠礼",
  [Map.GetPeach] = "【桃子】",
  [Map.GetAnalep] = "【酒】",
  [Map.GetSlash] = "【杀】",
  [Map.GetNan] = "【南蛮入侵】",
  [Map.GetWan] = "【万箭齐发】",
}
Map.BoderColor = {
  [Map.NorMonsterStr] = "#ff0033",
  [Map.EliteMonsterStr] = "#FF00FF",
  [Map.BoxStr] = "#ffff33",
  [Map.BossStr] = "#000000",
  [Map.ShopStr] = "#00ffcc",
  [Map.RestStr] = "#0099ff",
  [Map.OtherEventsStr] = "#ffffff",
  [Map.AddMaxHp] = "#ff3399",
  [Map.GetPeach] = "#00FF00",
  [Map.GetAnalep] = "#00FF00",
  [Map.GetSlash] = "#00FF00",
  [Map.GetNan] = "#00FF00",
  [Map.GetWan] = "#00FF00",
}

Map.ColumnDeep = 20  --根据mapItemsData配置节点总数量
Map.RowDeep = 9

function Map:initialize(player,data,obj)
  self.player = player
  self.wdtxobj = obj
  self.mapItemsData = data
  self:initMapData()
end

function Map:getMapItemsData()   --地图元素数据
  return self.mapItemsData[self.wdtxobj.storyid]
end

function Map:getNewMapData()   --地图数据
  local itemsdata = self:getMapItemsData()
  local data = table.clone(itemsdata)
  -- p(data)
  local totalnodes = 0
  for _, da in pairs(data) do
    totalnodes = totalnodes + da.num
    if da.node == Map.NorMonsterStr then
      da.num = da.num - 3
    end
  end

  local maps = {"boss","boss","boss"}
  for i = 1,totalnodes-3 do
    table.insert(maps,0)
  end
  table.insert(maps,"normonster")
  table.insert(maps,"normonster")
  table.insert(maps,"normonster")
  local findNode = function(cur,correct) 
    local emptynodes = {}
    -- local markpos --修正
    for i = 3,totalnodes do
      local pro = i / totalnodes
      if maps[i] == 0 and pro >= cur.progress[1] - correct and pro <= cur.progress[2] + correct then
        if cur.prohilink then
          if i ~= totalnodes then
            if maps[i-1] ~= cur.node and maps[i+1] ~= cur.node then
              table.insert(emptynodes,i)
            end
          else
            table.insert(emptynodes,i)
          end  
        else
          table.insert(emptynodes,i)
        end  
      end
    end
    if #emptynodes > 0 then
      return emptynodes[math.random(1,#emptynodes)],correct
    else
      correct = correct + 0.1
      -- error("找区域空节点找不到错误。（该区域节点都不是空节点问题）")
      return nil,correct
    end
  end

  local correct = 0
  while table.find(maps,function(item) return item == 0 end) do
    local curda = data[1]
    local randindex,cor = findNode(curda,correct)
    correct = cor
    local curprogress = randindex and randindex / totalnodes
    -- p(randindex)
    -- p(curda)
    -- p(curprogress)
    -- p(correct)
    -- dbg()
    if curprogress and curda.progress[1] - correct <= curprogress and curda.progress[2] + correct >= curprogress then
      correct = 0
      maps[randindex] = curda.node
      curda.num = curda.num - 1
      if curda.num == 0 then
        table.remove(data,1)
      end
    end
  end
  
  -- p(maps)
  -- p(#maps)
  -- dbg()
  return maps
end

function Map:getMapData()   --地图数据
  local data = {
    {node = Map.BoxStr,num=math.random(1,2),progress = {0.6,0.8},prohilink = true},
    {node = Map.EliteMonsterStr,num=math.random(1,2),progress = {0.5,0.7},prohilink = true},
    {node = Map.OtherEventsStr,num=math.random(3,4),progress = {0,0.65},prohilink = true},
    {node = Map.ShopStr,num=math.random(2,2),progress = {0.45,1},prohilink = true},   
    {node = Map.RestStr,num=math.random(2,3),progress = {0.33,1},prohilink = true},    
    {node = Map.NorMonsterStr,num=math.random(6,8),progress = {0,1},prohilink = false},
  }
  -- p(data)
  local totalnodes = 0
  for _, da in pairs(data) do
    totalnodes = totalnodes + da.num
    if da.node == Map.NorMonsterStr then
      da.num = da.num - 2
    end
  end

  local maps = {"normonster","normonster"}
  for i = 1,totalnodes-2 do
    table.insert(maps,0)
  end
  local findNode = function(cur,correct) 
    local emptynodes = {}
    -- local markpos --修正
    for i = 3,totalnodes do
      local pro = i / totalnodes
      if maps[i] == 0 and pro >= cur.progress[1] - correct and pro <= cur.progress[2] + correct then
        if cur.prohilink then
          if i ~= totalnodes then
            if maps[i-1] ~= cur.node and maps[i+1] ~= cur.node then
              table.insert(emptynodes,i)
            end
          else
            table.insert(emptynodes,i)
          end  
        else
          table.insert(emptynodes,i)
        end  
      end
    end
    if #emptynodes > 0 then
      return emptynodes[math.random(1,#emptynodes)],correct
    else
      correct = correct + 0.1
      -- error("找区域空节点找不到错误。（该区域节点都不是空节点问题）")
      return nil,correct
    end
  end

  local correct = 0
  while table.find(maps,function(item) return item == 0 end) do
    local curda = data[1]
    local randindex,cor = findNode(curda,correct)
    correct = cor
    local curprogress = randindex and randindex / totalnodes
    -- p(randindex)
    -- p(curda)
    -- p(curprogress)
    -- p(correct)
    -- dbg()
    if curprogress and curda.progress[1] - correct <= curprogress and curda.progress[2] + correct >= curprogress then
      correct = 0
      maps[randindex] = curda.node
      curda.num = curda.num - 1
      if curda.num == 0 then
        table.remove(data,1)
      end
    end
  end
  table.insert(maps,"boss")
  -- p(maps)
  -- p(#maps)
  -- dbg()
  return maps
end

function Map:openMapBox(columnlen,rowlen)   --打开地图
  columnlen = columnlen or Map.ColumnDeep
  rowlen = rowlen or Map.RowDeep
  local player = self.player
  local room = player.room
  local data = {}
  local reply = room:askToCustomDialog(player,{
    skill_name = "map_select",
    qml_path = "packages/wdtx/qml/MapChoiceBox.qml",
    extra_data = {
      "map_select",
      self.mapsdata,
      self.mapspos,
      columnlen,
      rowlen,
      self.nextcolpos,
      self.nextselcrows,
      Map.Enjoy,
      Map.BoderColor
    },
  })
  if reply ~= "" then
    reply = json.decode(reply)
    -- p(reply)
    -- dbg()
    if reply.choices then
      self.nextcolpos = reply.columnpos - 1
      local findNextPos = function(selrowpos,currow)
        local canpos = {}
        if currow[selrowpos] == 1 then
          table.insert(canpos,selrowpos)
        end
        if currow[selrowpos-1] and currow[selrowpos-1] == 1 then
          table.insert(canpos,selrowpos-1)
        end
        if currow[selrowpos+1] and currow[selrowpos+1] == 1 then
          table.insert(canpos,selrowpos+1)
        end
        return canpos
      end
      for i,column in ipairs(self.mapspos) do
        if i == self.nextcolpos then
          self.nextselcrows = findNextPos(reply.rowpos,column)
          break
        end
      end
      -- p(self.nextcolpos)
      -- p(self.nextselcrows)
      -- dbg()   
      table.insert(data,reply.choices)
      self.wdtxobj:refreshStory(data)
      -- return self:openMapBox(columnlen,rowlen)
    end
  else
    return self:openMapBox(columnlen,rowlen)
  end
end

function Map:initMapData()   --初始化地图数据
  local itemsdata = self:getMapItemsData()
  if not itemsdata then return end
  local data = self:getNewMapData()
  
  local findAliableDir = function(left,right,currows)
    local area = {}
    for i = left,right do
      if currows[i] == 0 then
        table.insert(area,i)
      end
    end
    if #area == 0 then
      return math.random(left, right)
    else
      return table.random(area)
    end
  end

  local maps = {{0,1,0,0,1,0,0,1,0}}
  -- local initpos = {{pos=2,dir=2},{pos=5,dir=2},{pos=8,dir=2}} --方向123，左中右
    local initpos = {2,5,8} --方向123，左中右
  local count = 6
  for i=1,19 do
    local currows = {0,0,0,0,0,0,0,0,0}
    for j = 1,#initpos do
      local curp = table.remove(initpos,1)
      local nextp = 0
      if curp == 1 then
        nextp = findAliableDir(curp, curp+1,currows)
      elseif curp == Map.RowDeep then
        nextp = findAliableDir(curp-1, curp,currows)
      else
        nextp = findAliableDir(curp-1, curp+1,currows)
      end
      if currows[nextp] == 0 then
        count = count + 1
        currows[nextp] = 1
        table.insert(initpos,nextp)
      else
        local progress = (i+2) / Map.ColumnDeep
        local removenode
        for _,config in ipairs(itemsdata) do
          if progress >= config.progress[1] and progress <= config.progress[2] then
            removenode = config.node
            break
          end
        end
        if removenode then
          -- p("删除")
          -- p(removenode)
          table.removeOne(data,removenode)
        end
      end
      
    end
    table.insert(maps,currows)
  end
  -- table.insert(maps,{0,1,0,0,1,0,0,1,0})
  -- p(count)
  -- -- p(data)
  -- p(#data)
  -- p("------------------分割线---------------")
  -- p(#maps)
  -- p(maps)
  
  -- dbg()

  self.mapsdata = data
  self.mapspos = maps
  self.nextcolpos = Map.ColumnDeep
  self.nextselcrows = {}
  -- self:openMapBox(20,9)
end

return Map
